/**
 * Notes: 本业务基本控制器
 * Date: 2021-03-15 19:20:00 
 */

const timeUtil = require('../../framework/utils/time_util.js');
const Controller = require('../../framework/client/controller.js');
const dataCheck = require('../../framework/validate/data_check.js');
const config = require('../../config/config.js');
const util = require('../../framework/utils/util.js');
const AppError = require('../../framework/core/app_error.js');
const appCode = require('../../framework/core/app_code.js');
const BaseService = require('../service/base_service.js');

global.PID = 'unknown';

class BaseController extends Controller {

	constructor(route, openId, event) {
		// 允许匿名访问的公共路由（仅读取型接口与回调），用于 HTTP 触发器在未携带 OPENID 时的兜底
		const PUBLIC_ROUTES = new Set([
			'payment/query_by_out_trade_no',
			'payment/query_by_transaction_id',
			'payment/callback',
			'payment/recharge_callback',
			'payment/device_callback',
			'device_order/callback'
		]);
		const isPublicRoute = PUBLIC_ROUTES.has(String(route || '').toLowerCase());

		// 在本地/测试环境或公共读取接口下，当未提供 OPENID 时使用匿名用户兜底
		const effectiveOpenId = openId || ((config.TEST_MODE || isPublicRoute) ? 'anonymous_user' : null);
		if (!effectiveOpenId) {
			console.error('OPENID is unfined');
			throw new AppError('OPENID is unfined', appCode.SVR);
		}

		super(route, effectiveOpenId, event);

		// 模板判定
		if (config.PID) {
			global.PID = config.PID;
		} else {
			if (event.PID) global.PID = event.PID;
		}

		console.log(`【↘event.PID=${event.PID}, global.PID=${global.PID}】`);

		// 严格使用来自云环境的 openId 作为唯一用户标识，拒绝客户端伪造的 userId
		// 仅当客户端提供的 userId 与 openId 一致时才用于校验，不覆盖服务端身份
		let clientUserId = event.params?.userId;
		let userId = effectiveOpenId;
		if (clientUserId && clientUserId !== effectiveOpenId) {
			console.warn(`客户端传入的 userId(${clientUserId}) 与 openId(${effectiveOpenId}) 不一致，已忽略客户端 userId`);
		}

		this._token = event.token || event.params?.token || '';

		this._userId = userId;

		// 当前时间戳
		this._timestamp = timeUtil.time();
		let time = timeUtil.time('Y-M-D h:m:s');

		console.log('------------------------');
		// console.log(`【${time}】【Request -- ↘↘↘】\n【↘Token = ${this._token}】\n【↘USER-ID = ${userId}】\n【↘↘IN DATA】=\n`, JSON.stringify(this._request, null, 4));
		console.log(`【${time}】【Request -- ↘↘↘】\n【↘Token = ${this._token}】\n【↘USER-ID = ${userId}】\n`);
	}

	/**
	 * 数据校验
	 * @param {*} rules 
	 */
	validateData(rules = {}) {
		let input = this._request;
		return dataCheck.check(input, rules);
	}

	// 取得某个具体的参数值
	getParameter(name) {
		let input = this._request;
		if (util.isDefined(input[name]))
			return input[name];
		else
			return '';
	}

	// 生产环境拒绝匿名用户的写操作守卫
	ensureAuthenticatedForWrite() {
		if (!config.TEST_MODE) {
			const uid = this._userId;
			if (!uid || uid === 'anonymous_user') {
				console.warn(`拒绝匿名用户写操作：uid=${uid}, TEST_MODE=false`);
				throw new AppError('生产环境禁止匿名用户进行写操作', appCode.LOGIC);
			}
		}
	}

	async initSetup() {
		// 在测试模式下跳过数据库初始化，避免本地缺失云密钥时报错
		if (config.TEST_MODE) {
			console.log('TEST_MODE: skip initSetup to avoid DB operations');
			return;
		}
		let service = new BaseService();
		await service.initSetup();
	}
}

module.exports = BaseController;